package cc.telecomdigital.tdstock.trading.Services;

import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;

import cc.telecomdigital.tdstock.R;
import cc.telecomdigital.tdstock.Framework.UniqueItem.DeviceInfo;
import cc.telecomdigital.tdstock.Framework.UniqueItem.TDStockLog;
import cc.telecomdigital.tdstock.Services.SoapTransport;
import cc.telecomdigital.tdstock.trading.Common.Trade_AppConstant;

import android.content.Context;
import android.os.Handler;
import android.os.Message;

public class TradeOrderPlace
{
	private final String	LOG_TAG	= "TradeOrderPlace";

	/** Call back interface for Placing a Trade Order **/
	public interface ITradeOrderPlaceResponse
	{
		/** if iSuccessfulSend == false, it means the there is a communication
		    error do not consider the iReponse as valid response **/
		void ResponseFunc(boolean iSuccessfulSend,
				TradeOrderPlaceResult iResponse);
	}

	public class TradeOrderPlaceResult
	{
		public boolean	Result;
		public String	StatusCode;
		public String	BrokerMessage;
		public String	RefNo;
		public String	BSSRefNo;

		/**		    
		 * @param iResult - being sent or not
		 * @param iStatusCode - return code from server
		 * @param iRefNo - reference number of the order for successful sent
		 * @param iBSSRefNo - server reference no for successful sent
		 * @param iBrokerMessage - broker message for successful sent
		 **/
		public TradeOrderPlaceResult(boolean iResult, String iStatusCode,
				String iRefNo, String iBSSRefNo, String iBrokerMessage)
		{
			Result = iResult;
			StatusCode = iStatusCode;
			BrokerMessage = iBrokerMessage;
			RefNo = iRefNo;
			BSSRefNo = iBSSRefNo;
		}
	}

	private final boolean debugMode = false;
	private SoapObject				soapRequest;
	private Context				callerContext;
	private boolean				demoData	= false;
	private Handler				messageHandler;
	private ITradeOrderPlaceResponse	responseHandler;

	/** Requesting for a Trade Order
	 * @param iContext - Owner
	 * @param iName - Server required userName
	 * @param iPassword - Server required password
	**/
	public TradeOrderPlace(Context iContext, String iName, String iPassword)
	{
		callerContext = iContext;

		soapRequest = new SoapObject(TradeAppInfo.NAMESPACE, "PlaceOrder");
		soapRequest.addProperty("DeviceID",
				TradeAppInfo.GetDeviceID(iContext));
		soapRequest.addProperty("UIN", TradeAppInfo.GetUIN());
		soapRequest.addProperty("ProtocolVer",
				TradeAppInfo.GetProtocolVersion());
		soapRequest.addProperty("BrokerID", TradeAppInfo.BrokerID);
		soapRequest.addProperty("ClientID", iName);
		soapRequest.addProperty("ClientPassword", iPassword);
		// E for Enhanced Price Limit Order "
		soapRequest.addProperty("OrderType", "E");
		// Form mickey's sample code
		soapRequest.addProperty("PreMarket", "N");
		soapRequest.addProperty("AllOrNothing", "");
		soapRequest.addProperty("Language", DeviceInfo.GetLanguageString());
	}

	public void Dispose()
	{		
		messageHandler = null;
		if (debugMode)
			TDStockLog.i(LOG_TAG, "We have no reference anymore");	
	}
	
	private String	orderReferenceNo;

	/**
	 * @param iStockCode - HKEX validated code
	 * @param iOrderSide - Order Action should wither by "B" or "A"
	 * @param iTradingPrice
	 * @param iTradingQuantity
	 * @return
	 **/
	public String SetPlaceOrder(String iStockCode, String iOrderSide,
			String iTradingPrice, String iTradingQuantity)
	{
		orderReferenceNo = iOrderSide + "R" + TradeAppInfo.CreateUniqueID();
		// Ref No is auto generate by the system for recognition for the order
		soapRequest.addProperty("RefNo", orderReferenceNo);
		soapRequest.addProperty("StockCode", iStockCode);
		// indicate as a cancel order
		soapRequest.addProperty("TradingType", iOrderSide);
		soapRequest.addProperty("TradingPrice", iTradingPrice);
		soapRequest.addProperty("TradingQty", iTradingQuantity);

		return orderReferenceNo;
	}

	/** Perform a send request for ordering.  place a return interface for handling the return data
	    If we are running a demo version, the iUseDemoData could be a fake send **/
	public void SendRequest(boolean iUseDemoData,
			ITradeOrderPlaceResponse iTradeOrderPlaceResponse)
	{
		demoData = iUseDemoData;
		responseHandler = iTradeOrderPlaceResponse;
		messageHandler = new Handler()
		{
			@Override
			public void handleMessage(Message msg)
			{
				if (responseHandler == null)
					return;

				switch (msg.what)
				{
					case REQUEST_DATA_SENT_FAIL:
						responseHandler.ResponseFunc(false, null);
						break;

					case REQUEST_DATA_SENT_SUCCESS:
						responseHandler.ResponseFunc(true,
								(TradeOrderPlaceResult) msg.obj);
						break;
				}
			}
		};
		// Start the Thread
		Thread internalThreadObj = new Thread()
		{
			// On purpose pass in to a message handler, so the thread can sleep or be
			// killed
			@Override
			public void run()
			{
				Message msg;
				TradeOrderPlaceResult infoData;

				// Provide success or fail reply
				msg = new Message();
				infoData = SendData(demoData);
				if ((infoData.Result == false) || (infoData.StatusCode == null)
						|| (infoData.StatusCode.length() == 0))
					msg.what = REQUEST_DATA_SENT_FAIL;
				else
				{
					msg.what = REQUEST_DATA_SENT_SUCCESS;
					msg.obj = infoData;
				}
				messageHandler.sendMessage(msg);
			}			
		};
		internalThreadObj.setName(LOG_TAG);
		internalThreadObj.start();
	}

	private final int	REQUEST_DATA_SENT_FAIL		= 0;
	private final int	REQUEST_DATA_SENT_SUCCESS	= 1;
	
	private TradeOrderPlaceResult SendData(boolean isDemoData)
	{
		//Prevent for multiple call for network
		synchronized(TradeAppInfo.padLock)
		{
			TradeOrderPlaceResult resultCode;
			SoapSerializationEnvelope envelope;
	
			String refNo;
			String bssRefNo;
			String statusCode;
			String brokerMessage;
	
			if (isDemoData == true)
			{
				try
				{
					Thread.sleep(Trade_AppConstant.demoHoldTime);
				}
				catch (InterruptedException e)
				{
					e.printStackTrace();
					TDStockLog.e(LOG_TAG, "SendData=>Exception: " + e.toString());
				}
				if (debugMode)
					TDStockLog.i(LOG_TAG, "Using Prepared Data");
				resultCode = new TradeOrderPlaceResult(true, "3", "11118", null,
						null);
				return resultCode;
			}
	
			if (DeviceInfo.IsNetworkAvailable(callerContext) == false)
			{
				resultCode = new TradeOrderPlaceResult(false, null, null, null,
						null);
				return resultCode;
			}
	
			envelope = new SoapSerializationEnvelope(TradeAppInfo.SOAP_VERSION);
	
			// Set packet ID
			soapRequest.addProperty("SeqNo", TradeAppInfo.GetSeqNo(true));
			// Last modification of the time
			soapRequest.addProperty(
					"Timestamp",
					TradeAppInfo.GetCurrentTimeStamp() + ","
							+ TradeAppInfo.GetSessionToken());
			envelope.setOutputSoapObject(soapRequest);
	
			refNo = null;
			bssRefNo = null;
			statusCode = null;
			brokerMessage = null;
	
			try
			{
				SoapObject resultsRequestSOAP;
				SoapObject soapResults;
				SoapTransport dataTransfer;
				
				if (TradeAppInfo.useSSLSetting)
					dataTransfer = new SoapTransport( callerContext, TradeAppInfo.GetURLAddress(true), 
						   				    		TradeAppInfo.SOAP_COMMUNIC_Timeout, R.raw.ca_stock);
				else
					dataTransfer = new SoapTransport( callerContext, TradeAppInfo.GetURLAddress(false), 
										   		TradeAppInfo.SOAP_COMMUNIC_Timeout);
							
				if (debugMode)
					TDStockLog.i(LOG_TAG, "Try sending Data");
				
				dataTransfer.SendData(TradeAppInfo.SOAP_SERVICENAME, envelope);
				
				resultsRequestSOAP = (SoapObject) envelope.bodyIn;
				if (debugMode)
					TDStockLog.i(LOG_TAG, "Parsing Data");			
				soapResults = (SoapObject) resultsRequestSOAP
						.getProperty("PlaceOrderResult");
	
				statusCode = TradeAppInfo.GetSoapProperty(soapResults, LOG_TAG,
						"StatusCode");
				refNo = TradeAppInfo.GetSoapProperty(soapResults, LOG_TAG,
						"RefNo");
				bssRefNo = TradeAppInfo.GetSoapProperty(soapResults, LOG_TAG,
						"BssRefNo");
				brokerMessage = TradeAppInfo.GetSoapProperty(soapResults,
						LOG_TAG, "Message");
			}
			catch (java.net.SocketTimeoutException e)
			{
				e.printStackTrace();
				TDStockLog.e(LOG_TAG, "Timeout: " + e.toString());
				resultCode = new TradeOrderPlaceResult(false, null, null, null,
						null);
				return resultCode;
			}
			catch (Exception e)
			{
				e.printStackTrace();
				TDStockLog.e(LOG_TAG, e.toString());
				resultCode = new TradeOrderPlaceResult(false, null, null, null,
						null);
				return resultCode;			
			}
	
			resultCode = new TradeOrderPlaceResult(true, statusCode, refNo,
					bssRefNo, brokerMessage);
	
			return resultCode;
		}
	}
}
